import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.net.ServerSocket;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.Vector;

public class Tools
{

	public static boolean TRACE_FLUX = true;
	

	private static Boolean stateBit(byte b, int bit)
	{
		return (b & (1 << bit)) != 0;
	}


	public static Vector<Integer> getIndexFromBufferMap(byte[] buf)
	{
		Vector<Integer> v = new Vector<Integer>();
		
		for(int i=0; i<buf.length; i++)
			for(int b=0; b<8; b++)
				if(Tools.stateBit(buf[i], b))
					v.add(i*8+b);
				
		return v;
	}



	public static void treatResponse(String str)
	{
		if(str == null)
			return;

		String tab[] = str.split(" ");
		
		if(tab[0].equals("list"))
			treatLook(str.substring(6, str.length()-1));
		else if(tab[0].equals("peers"))
			treatGetFile(str.substring(6, 38), str.substring(40, str.length()-1));
	}
	
	public static void treatGetFile(String key, String str)
	{
		if(str.equals(""))
			return;
			
		String tab[] = str.split(" ");
		
		for(int i=0; i < tab.length; i++)
		{
			Peer p = new Peer(tab[i]);
			Bdd.PEER_FOR_FILE.put(key, p);
			
			Leecher l = new Leecher(key, p);
			l.start();
		}

	}
	
	public static void treatLook(String str)
	{
		int i=0;
		String tab[] = str.split(" ");

		while(i < tab.length)
		{
			Bdd.ON_TRACKER.put(tab[i+3], new FileData(tab[i], Long.parseLong(tab[i+1]), Integer.parseInt(tab[i+2]), tab[i+3]));
			i += 4;
		}
	}
	

	public static void traceFluxSend(String s)
	{
		if(TRACE_FLUX)
			System.out.println("send : "+s);
	}
	
	public static void traceFluxReceive(String s)
	{
		if(TRACE_FLUX)
			System.out.println("receive : "+s);
	}
	
	public static void initConfig()
	{
		BufferedReader fread = null;
		String line = "";
                
		try {
			fread = new BufferedReader(new FileReader(new File(Config.FILE_CONF)));
		}catch(IOException e){}
                
                if (fread == null) {
                    try {
                        fread = new BufferedReader(new FileReader(new File("client\\" + Config.FILE_CONF)));
                    } catch (IOException e) {}
                }
                
		int i=0;
		do 
		{
			try
			{
				line = fread.readLine();
			
				if (line != null && !(line.equals("")) && !(line.substring(0,1).equals("%")))
				{
					switch(i)
					{
						case 0:
							Config.SERVER_IP = line;
							i++;
							break;
						
						case 1:
							Config.SERVER_PORT = Integer.parseInt(line);
							i++;
							break;
							
						case 2:
							Config.MAX_PEER = Integer.parseInt(line);
							i++;
							break;
						
						case 3:
							Config.INTERVAL_MAJ = Integer.parseInt(line);
							i++;
							break;
						
						case 4:
							Config.SIZE_PIECES = Integer.parseInt(line);
							i++;
							break;
					}
				}
			}catch(IOException e){}
				
		}while(line != null && i<3);
		
		try
		{
			fread.close();
		}catch(IOException e){}
	}
	
	public static String MD5(String s)
	{
		try
		{
		
			MessageDigest md = MessageDigest.getInstance("MD5");
			md.update(s.getBytes());
			byte[] md5_b = md.digest();
			
			StringBuilder md5 = new StringBuilder(2*md5_b.length);
			byte[] Hexhars = {
				'0', '1', '2', '3', '4', '5',
				'6', '7', '8', '9', 'a', 'b',
				'c', 'd', 'e', 'f' 
			};
			
			for (int i = 0; i < md5_b.length; i++) 
			{
				int v = md5_b[i] & 0xff;
				md5.append((char)Hexhars[v >> 4]);
				md5.append((char)Hexhars[v & 0xf]);
			}

			return md5.toString();
			
		}
		catch(NoSuchAlgorithmException e){
			return null;
		}
	}
	
	
	public static int getFreePort()
	{
		ServerSocket s;
		
		try{
			s = new ServerSocket(0);
		}catch(IOException e){
			return 0;
		}
		
		return s.getLocalPort();
	}
	
	
	public static String getStringAnnounce(int port)
	{
		String s = "announce listen "+port+" seed [";
		
		Set keys = Bdd.SEED_MAP.keySet();
		Iterator it = keys.iterator();
		String seed_list = "";
		while (it.hasNext())
		{
			seed_list += Bdd.SEED_MAP.get(it.next()).format()+" ";
		}
		
		if(!seed_list.equals(""))
			seed_list = seed_list.substring(0, seed_list.length()-1);
		
		s += seed_list+"] ";
		s += "leech [";
		
		String leech_list = "";
		for(int i=0; i<Bdd.LEECH_LIST.size(); i++)
			leech_list += Bdd.LEECH_LIST.get(i)+" ";
			
		if(!leech_list.equals(""))
			leech_list = leech_list.substring(0, leech_list.length()-1);
			
		s += leech_list+"]";
		return s;
	}
	
	
	public static String getStringLook(String filename)
	{
		return "look [filename=\""+filename+"\"]";
	}
	
	
	public static String getStringGetfile(String key)
	{
		return "getfile "+key;
	}
	
	
	public static String getStringInterested(String key)
	{
		return "interested "+key;
	}
	
	
	public static String getStringPieces(String key, Vector<Integer> v_index)
	{
		String s = "getpieces "+key+" [";
		String pieces_list = "";
		
		for(int i=0; i<v_index.size(); i++)
			pieces_list += v_index.get(i)+" ";
			
		if(!pieces_list.equals(""))
			pieces_list = pieces_list.substring(0, pieces_list.length()-1);
		
		s += pieces_list+"]";
		
		return s;
	}
	
	
	/*public static String getStringHave(String key, String binaire)
	{
		return "have "+key+" "+binaire;
	}*/
	
	public static String getStringUpdate()
	{
		String s = "update seed [";
		String seed_l = "";
		
		for (Map.Entry<String, FileData> entry : Bdd.SEED_MAP.entrySet()) 
			seed_l += entry.getKey()+" ";
			
		if(!seed_l.equals(""))
			seed_l = seed_l.substring(0, seed_l.length()-1);
			
		s += seed_l+"] leech [";
		
		
		String leech_l = "";
		
		for (Map.Entry<String, FileData> entry : Bdd.LEECH_LIST.entrySet()) 
			leech_l += entry.getKey()+" ";
			
		if(!leech_l.equals(""))
			leech_l = leech_l.substring(0, leech_l.length()-1);
			
		s += leech_l+"]";
		
		return s;
	}
	
}
